#include "interrupt_key.h"

static int key_probe(struct platform_device *pdev);
static int key_remove(struct platform_device *pdev);

/* 匹配列表，用于设备树和平台驱动匹配 */
static const struct of_device_id key_of_match[] = {
	{.compatible = "atk,key"},
	{ /* Sentinel */ }
};
//平台驱动
static struct platform_driver key_drv = {
	.driver = {
		.name = "key",
		.owner = THIS_MODULE,
		.pm = NULL,
		.of_match_table = key_of_match,
	},
	.probe = key_probe,
	.remove = key_remove,
};

//key句柄列表
static struct list_head key_list = LIST_HEAD_INIT(key_list);

//根据ID查找设备句柄
static struct key_handle *find_key_handle(uint32_t id)
{
	struct key_handle *pos;
	struct key_handle *n;
	struct key_handle *key_handle;

	key_handle = NULL;
	list_for_each_entry_safe(pos, n, &key_list, node)
	{
		if(pos->id == id)
		{
			key_handle = pos;
			break;
		}
	}

	return key_handle;
}

static irqreturn_t key_handler(int irq, void *dev)
{
	struct key_handle *key_handle;

	key_handle = (struct key_handle*)dev;
#ifdef USING_TASKLET
	//调度tasklet
	tasklet_schedule(&key_handle->tasklet);
#else
	//调度工作队列
	schedule_work(&key_handle->work);
#endif
	//返回IRQ_HANDLED，表示中断被成功处理
	return IRQ_HANDLED;
}

#ifdef USING_TASKLET
static void key_tasklet(unsigned long arg)
{
	struct key_handle *key_handle;

	printk("key_tasklet\r\n");
	
	key_handle = (struct key_handle*)arg;
	//设置定时器到期时间，如果定时器没有注册则会将其注册
	mod_timer(&key_handle->timer, jiffies + msecs_to_jiffies(10));

}
#else
static void key_work(struct work_struct *w)
{
	struct key_handle *key_handle;

	printk("key_work\r\n");
	
	key_handle = (struct key_handle*)container_of(w, struct key_handle, work);
	//设置定时器到期时间，如果定时器没有注册则会将其注册
	mod_timer(&key_handle->timer, jiffies + msecs_to_jiffies(10));
}
#endif

static void timer_func(struct timer_list *tm)
{
	struct key_handle *key_handle;

	key_handle = (struct key_handle*)container_of(tm, struct key_handle, timer);
	//上报GPIO状态
	input_report_key(key_handle->inputdev, key_handle->key_code, gpiod_get_value(key_handle->key_gpio));
	//上报完成
	input_sync(key_handle->inputdev);
}

//设备和驱动匹配成功执行
static int key_probe(struct platform_device *pdev)
{
	int result;
	uint32_t id;
	uint32_t irq_flags;
	uint32_t key_code;
	const char *labe;
	struct key_handle *key_handle;

	printk("function:%s line:%d\n", __FUNCTION__, __LINE__);

	//按从小到大顺序生成ID
	for(id=0; (find_key_handle(id)) && (id<KEY_NUMBER); id++)
	{
		;
	}
	//ID必须小于注册的最大ID号
	if(id >= KEY_NUMBER)
	{
		printk("dev id invalid\r\n");
		return -EINVAL;
	}

	//设置平台设备ID
	pdev->id = id;

	//获取按键对应的按键值
	result = of_property_read_u32(pdev->dev.of_node, "key-code", &key_code);
	if(result != 0)
	{
		printk("get key-code failed\r\n");
		return result;
	}

	//获取labe
	result = of_property_read_string(pdev->dev.of_node, "labe", &labe);
	if(result < 0)
	{
		printk("get labe failed\r\n");
		return result;
	}

	//分配设备句柄
	key_handle = devm_kzalloc(&pdev->dev, sizeof(struct key_handle), GFP_KERNEL);
	if(!key_handle)
	{
		printk("alloc memory faikey\r\n");
		return -ENOMEM;
	}

	//绑定ID
	key_handle->id = id;
	//绑定按键值
	key_handle->key_code = key_code;

	//分配输入设备
	key_handle->inputdev = devm_input_allocate_device(&pdev->dev);
	if(!key_handle->inputdev)
	{
		printk("alloc input device failed");
		return -ENOMEM;
	}
	//设置输入设备名称
	key_handle->inputdev->name = labe;
	//设置事件类型，按键事件、重复事件
	__set_bit(EV_KEY, key_handle->inputdev->evbit);
	__set_bit(EV_REP, key_handle->inputdev->evbit);
	//设置事件码
	__set_bit(key_handle->key_code, key_handle->inputdev->keybit);
	//注册输入设备
	result = input_register_device(key_handle->inputdev);
	if(result)
	{
		printk("register input device failed");
		return result;
	}

	//初始化消抖定時器
	timer_setup(&key_handle->timer, timer_func, 0);

#ifdef USING_TASKLET
	//初始化tasklet
	tasklet_init(&key_handle->tasklet, key_tasklet, (unsigned long)key_handle);
#else
	//初始化工作队列
	INIT_WORK(&key_handle->work, key_work);
#endif

	//获取GPIO，并设置为输入
	key_handle->key_gpio = devm_gpiod_get(&pdev->dev, "key", GPIOD_IN);
	if(IS_ERR(key_handle->key_gpio))
	{
		printk("get gpio faikey\r\n");
		return PTR_ERR(key_handle->key_gpio);
	}

	//获取中断号
	key_handle->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
	//获取中断触发方式
	irq_flags = irq_get_trigger_type(key_handle->irq);
	if(irq_flags == IRQF_TRIGGER_NONE)
		irq_flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
	//注册中断
	result = devm_request_irq(&pdev->dev, key_handle->irq, key_handler, irq_flags, "key", (void*)key_handle);
	if(result != 0)
	{
		printk("request irq failed\r\n");
		return result;
	}

	//加入设备句柄链表
	list_add(&key_handle->node, &key_list);

	//设置平台设备的驱动私有数据
	pdev->dev.driver_data = (void*)key_handle;

	return 0;
}

//设备或驱动卸载时执行
static int key_remove(struct platform_device *pdev)
{
	struct key_handle *key_handle;

	printk("%s\r\n", __FUNCTION__);

	//提取平台设备的驱动私有数据
	key_handle = (struct key_handle*)pdev->dev.driver_data;
	//从设备句柄链表中删除
	list_del(&key_handle->node);
	//从内核删除定时器
	del_timer(&key_handle->timer);
	//注销输入设备
	input_unregister_device(key_handle->inputdev);

	return 0;
}

static int __init key_drv_init(void)
{
	int result;

	printk("%s\r\n", __FUNCTION__);

	//注册平台驱动
	result = platform_driver_register(&key_drv);
	if(result < 0)
	{
		printk("add cdev faikey\r\n");
		return result;
	}

	return 0;
}

static void __exit key_drv_exit(void)
{
	printk("%s\r\n", __FUNCTION__);

	//注销平台驱动
	platform_driver_unregister(&key_drv);
}

module_init(key_drv_init);
module_exit(key_drv_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("LF");
MODULE_DESCRIPTION("key_dev");
